﻿using System;
using System.Collections.Generic;
using System.Linq;

namespace ObjectPool
{
    struct ManagedObject<T> where T : IManaged
    {
        string id;
        T target;

        public static ManagedObject<T> Create(T target)
        {
            return new ManagedObject<T>
            {
                id = Guid.NewGuid().ToString("N"),
                target = target
            };
        }

        public static bool operator ==(ManagedObject<T> a, object b)
        {
            if (b == null)
            {
                return false;
            }
            if (b is T)
            {
                return a.target.Equals(b) && a.target.GetHashCode() == b.GetHashCode();
            }
            if (b is ManagedObject<T> tmp)
            {
                return a.id == tmp.id;
            }
            return false;
        }

        public static bool operator !=(ManagedObject<T> a, object b)
        {

            return false;
        }
    }

    public class TimedObjectPool<T> : IObjectPool<T> where T : IManaged
    {
        private LinkedList<ManagedObject<T>> _storedObjects;


        public TimedObjectPool(int capacity, long aliveMsec)
        {
            Capacity = capacity;
            AliveMsec = aliveMsec;
            _storedObjects = new LinkedList<ManagedObject<T>>();
        }


        public int Count { get; private set; }

        public int Capacity { get; private set; }

        public long AliveMsec { get; private set; }


        public bool Store(T managedObject)
        {
            if (_storedObjects.Count == Capacity)
            {
                return false;
            }
            if (_storedObjects.Contains(managedObject))
            {
                return false;
            }
            managedObject.Init();
            (managedObject as IManagedEvent)?.OnStore();

            _storedObjects.AddLast(managedObject);
            return true;
        }

        public T Extract()
        {

            T obj = _storedObjects.First();
            if (obj == null)
            {
                return obj;
            }
            (obj as IManagedEvent)?.OnExtract();

            _storedObjects.RemoveFirst();
            return obj;
        }

        

        public bool Restore(T managedObject)
        {
            throw new NotImplementedException();
        }

        

        public void Release(T managedObject)
        {
            throw new NotImplementedException();
        }

        public void Release()
        {
            throw new NotImplementedException();
        }

        public void Clear()
        {
            foreach (var o in _storedObjects)
            {
                (o as IManagedEvent)?.OnRelease();
                o.Clear();
            }
            _storedObjects.Clear();
        }
    }
}
